/* 
 *  Copyright 2012 CodeMagi, Inc.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.codemagi.servlets.search;

import com.codemagi.login.AccessException;
import com.codemagi.login.LoginException;
import com.codemagi.servlets.AppException;
import com.codemagi.servlets.search.beans.*;
import com.codemagi.util.*;
import com.lowagie.text.*;
import com.lowagie.text.pdf.*;
import java.awt.Color;
import java.io.*;
import java.util.*;
import javax.servlet.http.*;
import org.apache.log4j.*;

/**
 * This class overrides the base SearchController class to add functionality for creating PDFs of search results 
 * using iText by Bruno Lowagie and Paolo Soares:
 * 
 * http://www.lowagie.com/iText
 *
 * @version 1.0
 * @author August Detlefsen for CodeMagi, Inc.
 */
public abstract class SearchControllerIText extends com.codemagi.servlets.search.SearchController {

    Logger log = Logger.getLogger(this.getClass());

    //some default fonts
    protected static final Font FONT_ITEM  =
	FontFactory.getFont(FontFactory.HELVETICA, 6, Font.NORMAL, new Color(0,0,0));
    
    protected static final Font FONT_HEADER  =
        FontFactory.getFont(FontFactory.HELVETICA, 6, Font.BOLD, new Color(255,255,255));

    protected static final Font FONT_TINY =
        FontFactory.getFont(FontFactory.HELVETICA, 1, Font.NORMAL, new Color(0,0,0));

    protected static final Color COLOR_TITLE_BG   = new Color(0,0,0);


    //some default layouts
    protected static final Cell DEFAULT_CELL_LAYOUT_LEFT = new Cell();
    static {
	DEFAULT_CELL_LAYOUT_LEFT.setBorder(Rectangle.BOX);
	DEFAULT_CELL_LAYOUT_LEFT.setHorizontalAlignment(Element.ALIGN_LEFT);
	try {
	    DEFAULT_CELL_LAYOUT_LEFT.addElement(new Phrase("", FONT_TINY) );
	} catch (BadElementException bee) {
	}
    }
    
    protected static final Cell DEFAULT_CELL_LAYOUT = DEFAULT_CELL_LAYOUT_LEFT;

    protected static final Cell DEFAULT_CELL_LAYOUT_RIGHT = new Cell();
    static {
	DEFAULT_CELL_LAYOUT_RIGHT.setBorder(Rectangle.BOX);
	DEFAULT_CELL_LAYOUT_RIGHT.setHorizontalAlignment(Element.ALIGN_RIGHT);
	try {
	    DEFAULT_CELL_LAYOUT_RIGHT.addElement(new Phrase("", FONT_TINY) );
	} catch (BadElementException bee) {
	}
    }
    
    protected static final Cell DEFAULT_CELL_LAYOUT_CENTER = new Cell();
    static {
	DEFAULT_CELL_LAYOUT_CENTER.setBorder(Rectangle.BOX);
	DEFAULT_CELL_LAYOUT_CENTER.setHorizontalAlignment(Element.ALIGN_CENTER);
	try {
	    DEFAULT_CELL_LAYOUT_CENTER.addElement(new Phrase("", FONT_TINY) );
	} catch (BadElementException bee) {
	}
    }
    
    protected static final Cell DEFAULT_HEADER_LAYOUT_LEFT = new Cell();
    static {
	DEFAULT_HEADER_LAYOUT_LEFT.setBorder(Rectangle.BOX);
	DEFAULT_HEADER_LAYOUT_LEFT.setBackgroundColor(COLOR_TITLE_BG);
	DEFAULT_HEADER_LAYOUT_LEFT.setBorderColor(new Color(255,255,255));
	DEFAULT_HEADER_LAYOUT_LEFT.setHeader(true);
	DEFAULT_HEADER_LAYOUT_LEFT.setHorizontalAlignment(Element.ALIGN_LEFT);
	try {
	    DEFAULT_HEADER_LAYOUT_LEFT.addElement(new Phrase("", FONT_TINY) );
	} catch (BadElementException bee) {
	}
    }

    protected static final Cell DEFAULT_HEADER_LAYOUT = DEFAULT_HEADER_LAYOUT_LEFT;

    protected static final Cell DEFAULT_HEADER_LAYOUT_RIGHT = new Cell();
    static {
	DEFAULT_HEADER_LAYOUT_RIGHT.setBorder(Rectangle.BOX);
	DEFAULT_HEADER_LAYOUT_RIGHT.setBackgroundColor(COLOR_TITLE_BG);
	DEFAULT_HEADER_LAYOUT_RIGHT.setBorderColor(new Color(255,255,255));
	DEFAULT_HEADER_LAYOUT_RIGHT.setHeader(true);
	DEFAULT_HEADER_LAYOUT_RIGHT.setHorizontalAlignment(Element.ALIGN_RIGHT);
	try {
	    DEFAULT_HEADER_LAYOUT_RIGHT.addElement(new Phrase("", FONT_TINY) );
	} catch (BadElementException bee) {
	}
    }

    protected static final Cell DEFAULT_HEADER_LAYOUT_CENTER = new Cell();
    static {
	DEFAULT_HEADER_LAYOUT_CENTER.setBorder(Rectangle.BOX);
	DEFAULT_HEADER_LAYOUT_CENTER.setBackgroundColor(COLOR_TITLE_BG);
	DEFAULT_HEADER_LAYOUT_CENTER.setBorderColor(new Color(255,255,255));
	DEFAULT_HEADER_LAYOUT_CENTER.setHeader(true);
	DEFAULT_HEADER_LAYOUT_CENTER.setHorizontalAlignment(Element.ALIGN_CENTER);
	try {
	    DEFAULT_HEADER_LAYOUT_CENTER.addElement(new Phrase("", FONT_TINY) );
	} catch (BadElementException bee) {
	}
    }


    /**
     * Dispatches <code>pdf</code> actions. Returns result set as a tab-delimited fils. 
     */
    protected String dispatchPdf(HttpServletRequest request, HttpServletResponse response) 
	throws LoginException, AccessException {

        log.debug("***** dispatchPdf *****");

        //next page if operation is successful                                                                            
        String nextPage = VIEW_RESULTS;
	//log.debug("about to try in dispatchPdf\n");

	try {
	    //get session                                                                                                      
	    HttpSession session = request.getSession();
	    
	    //get SearchBean from session                                                                                  
	    ISearchBean bean = (ISearchBean)session.getAttribute(beanName);
	    log.debug("Bean name is " + beanName + "\n");

	    if (bean == null) throw new AppException(MSG_NO_SEARCH);

	    GridList results = getResults(bean);
	    int numRows = results.getNumRows();
	    int numCols = results.getNumCols();

	    response.setContentType("application/pdf");
	    response.setHeader("Content-Disposition", "attachment; filename=results.pdf;");
	    
	    //    log.debug("about to mess with documents here \n");
            Document document = new Document(PageSize.LETTER.rotate(), 36, 18, 18, 18);
	    PdfWriter writer = PdfWriter.getInstance(document, response.getOutputStream());
            document.open();
	    log.debug("calling getTable()\n");
	    document.add(getTable(results));
	    document.close();

	    nextPage = VIEW_PDF;
	    
	} catch (AppException e) {
	    log.debug("", e);
	    
	    request.setAttribute("error_message", e.getMessage());

	} catch (IOException ie) {
	    log.debug("", ie);

	    request.setAttribute("error_message", MSG_UNKNOWN_ERROR);

	} catch (DocumentException de) {
	    log.debug("", de);

            request.setAttribute("error_message", MSG_UNKNOWN_ERROR);
	}
	
        return nextPage;
    }
    

    //PDF METHODS --------------------------------------------------

    /**
     * Returns a suitable table for PDF generator. Meant to be overridden.
     */
    protected Table getTable(GridList g) throws BadElementException {


	log.debug("*******getTable()********\n");

	Table t = new Table(g.getNumCols());

	if (g != null) {
	    
	    log.debug("*******GridList is not null and has dimensions " + g.getNumRows() +" rows by " + g.getNumCols() + " cols********\n");
	    t.setWidth(100f);
	    t.setAutoFillEmptyCells(true);
	    t.setPadding(3);
	    
	    t.setDefaultLayout(DEFAULT_HEADER_LAYOUT);
	    
	    for (int i=0; i<g.getNumCols(); i++) {
		
		//		log.debug("Adding column name " + g.getColumnName(i) + " " + i + " of " + g.getNumCols() + "\n");
		t.addCell( new Phrase(Utils.noNulls(g.getColumnName(i)), FONT_HEADER) );
	    }
	    
	    t.setDefaultLayout(DEFAULT_CELL_LAYOUT);
	    t.endHeaders();
	    
	    //	    log.debug("***Ending headers***\n");

	    for (int j=0; j<g.getNumRows(); j++) {
		
		for (int k=0; k<g.getNumCols(); k++) {
		    
		    //		    log.debug("About to add cell at row "+ j +", col "+ k +"\n");
		    t.addCell( new Phrase((String)Utils.noNulls(g.getItem(j,k)), FONT_ITEM) );
		}
	    }
	}
	return t;
    }


    /**
     * Returns a suitable table for PDF generator. Takes a OrderedTable of pretty names and column names.
     */
    protected Table getTable(GridList g, OrderedTable o) throws BadElementException {


	log.debug("*******getTable()********\n");

	Vector prettyName = o.orderedKeys();
	java.util.List colName = o.orderedValues();
	Table t = new Table(prettyName.size());

	if (g != null && prettyName != null && colName != null) {
	    
	    log.debug("*******GridList, prettyName, colName are not null and have dimensions " + g.getNumRows() +" rows by " + prettyName.size() + " cols********\n");
	    t.setWidth(100f);
	    t.setAutoFillEmptyCells(true);
	    t.setPadding(3);
	    
	    t.setDefaultLayout(DEFAULT_HEADER_LAYOUT);
	    
	    for (int i=0; i<prettyName.size(); i++) {
		
		//		log.debug("Adding column name " + g.getColumnName(i) + " " + i + " of " + g.getNumCols() + "\n");
		t.addCell( new Phrase((String)Utils.noNulls(prettyName.get(i)), FONT_HEADER) );
	    }
	    
	    t.setDefaultLayout(DEFAULT_CELL_LAYOUT);
	    t.endHeaders();
	    
	    //	    log.debug("***Ending headers***\n");

	    for (int j=0; j<g.getNumRows(); j++) {
		
		for (int k=0; k<colName.size(); k++) {
		    
		    //		    log.debug("About to add cell at row "+ j +", col "+ k +"\n");
		    //log.debug("***** trying to get colname "+ colName.get(k)+ " ******\n");
		    t.addCell( new Phrase((String)Utils.noNulls(g.getItem(j,(String)colName.get(k))), FONT_ITEM) );
		}
	    }
	}
	return t;
    }

    /**
     * Returns a suitable table for PDF generator. Takes a OrderedTable of pretty names and column names and the table itself.
     */
    protected Table getTable(GridList g, OrderedTable o, Table t) throws BadElementException {


	log.debug("*******getTable()********\n");

	Vector prettyName = o.orderedKeys();
	java.util.List colName = o.orderedValues();

	if (g != null && prettyName != null && colName != null && t != null && (t.columns() == colName.size()) ) {
	    
	    log.debug("*******GridList, prettyName, colName are not null and have dimensions " + g.getNumRows() +" rows by " + prettyName.size() + " cols; t and o have same number of columns********\n");
	    
	    t.setDefaultLayout(DEFAULT_HEADER_LAYOUT);
	    
	    for (int i=0; i<prettyName.size(); i++) {
		
		t.addCell( new Phrase((String)Utils.noNulls(prettyName.get(i)), FONT_HEADER) );
	    }
	    
	    t.setDefaultLayout(DEFAULT_CELL_LAYOUT);
	    t.endHeaders();
	    
	    for (int j=0; j<g.getNumRows(); j++) {
		
		for (int k=0; k<colName.size(); k++) {
		    
		    t.addCell( new Phrase((String)Utils.noNulls(g.getItem(j,(String)colName.get(k))), FONT_ITEM) );
		}
	    }
	}
	return t;
    }

    /**
     * Returns a suitable table for PDF generator. Takes a OrderedTable of pretty names and column names and the table itself and an OrderedTable of column justifications.
     */
    protected Table getTable(GridList g, OrderedTable o, Table t, OrderedTable just) throws BadElementException {


	log.debug("*******getTable()********\n");

	Vector prettyName = o.orderedKeys();
	java.util.List colName = o.orderedValues();

	if ( (g != null) && (prettyName != null) && (colName != null) && (t != null) && (just != null) && (t.columns() == colName.size()) && (t.columns() == just.size()) ) {
	    
	    log.debug("*******GridList, prettyName, colName are not null and have dimensions " + g.getNumRows() +" rows by " + prettyName.size() + " cols; t and o have same number of columns********\n");
	    
	    t.setDefaultLayout(DEFAULT_HEADER_LAYOUT);
	    
	    for (int i=0; i<prettyName.size(); i++) {
		
		t.addCell( new Phrase((String)Utils.noNulls(prettyName.get(i)), FONT_HEADER) );
	    }
	    
	    t.setDefaultLayout(DEFAULT_CELL_LAYOUT);
	    t.endHeaders();
	    
	    for (int j=0; j<g.getNumRows(); j++) {
		
		for (int k=0; k<colName.size(); k++) {
		    
		    if (colName.get(k) == null || just.get(colName.get(k)) == null ) {
			t.setDefaultLayout(DEFAULT_CELL_LAYOUT);
		    } else {
			t.setDefaultLayout((Cell)just.get(colName.get(k)));
		    }
		    t.addCell( new Phrase((String)Utils.noNulls(g.getItem(j,(String)colName.get(k))), FONT_ITEM) );
		}
	    }
	}
	return t;
    }

}
